﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using System.Text;

namespace GomeeSoft.src.classes
{
    static class Calendar
    {
        private static DataTable holidayDataTable;

        // Date Type
        #region DateType
        public static DateTime GetDateTime(int year, int month, int row, int col)
        {
            DateTime baseDate = new DateTime(year, month, 1);
            switch (baseDate.DayOfWeek)
            {
                case DayOfWeek.Sunday:
                    return baseDate.AddDays(row * 7 + col);
                case DayOfWeek.Monday:
                    return baseDate.AddDays(row * 7 + col - 1);
                case DayOfWeek.Tuesday:
                    return baseDate.AddDays(row * 7 + col - 2);
                case DayOfWeek.Wednesday:
                    return baseDate.AddDays(row * 7 + col - 3);
                case DayOfWeek.Thursday:
                    return baseDate.AddDays(row * 7 + col - 4);
                case DayOfWeek.Friday:
                    return baseDate.AddDays(row * 7 + col - 5);
                case DayOfWeek.Saturday:
                    return baseDate.AddDays(row * 7 + col - 6);
            }
            return baseDate;
        }

        public static DateType GetDateType(String country, DateTime date)
        {
            if (IsHoliday(country, date))
                return DateType.Holiday;
            else if (date.DayOfWeek == DayOfWeek.Sunday)
                return DateType.Sunday;
            else if (date.DayOfWeek == DayOfWeek.Saturday)
                return DateType.Saturday;
            else
                return DateType.Workday;
        }

        static public bool IsHoliday(string country, DateTime date)
        {
            RetreiveHolidayList(country);
            SetRealDate(date);
            return CheckHoliday(date);
        }

        static private void RetreiveHolidayList(string country)
        {
            if (holidayDataTable == null)
            {
                SQLiteQuery query = new SQLiteQuery();
                query.SetCommand(GomeeSoft.Properties.Resources.SQLHolidayCheck);
                query.SetParameter("@country", country);
                holidayDataTable = query.SelectDataTable();
                holidayDataTable.Columns.Add(new DataColumn("RealDate", Type.GetType("System.DateTime")));
            }
        }

        static private void SetRealDate(DateTime date)
        {
            for (int i = 0; i < holidayDataTable.Rows.Count; i++)
            {
                DataRow row = holidayDataTable.Rows[i];
                row.SetField<DateTime>("RealDate", GetRealDate(row, date.Date.Year));
            }
        }

        static private DateTime GetRealDate(DataRow row, int year)
        {
            DateTime tmp = new DateTime();
            int tmpYear, tmpMonth, tmpDay, dayDiff;
            string tmpCalendarType;

            try
            {
                if (row.IsNull("RealDate") || row.Field<DateTime>("RealDate").Date.Year != year)
                {
                    tmpCalendarType = (String)row.Field<string>("calendar_type");
                    tmpYear = (int)row.Field<long>("year");
                    tmpMonth = (int)row.Field<long>("month");
                    tmpDay = (int)row.Field<long>("day");
                    dayDiff = (int)row.Field<long>("daydiff");

                    switch (tmpCalendarType)
                    {
                        case "01":
                            if (tmpYear > 0)
                                tmp = new DateTime(tmpYear, tmpMonth, tmpDay);
                            else
                                tmp = new DateTime(year, tmpMonth, tmpDay);
                            break;
                        case "02":
                            if (tmpYear > 0)
                            {
                                tmp = ToDateTime(new LunarDate(tmpYear, tmpMonth, tmpDay, false));
                            }
                            else
                            {
                                tmp = ToDateTime(new LunarDate(year, tmpMonth, tmpDay, false));
                                if (tmp.Date.Year > year)
                                    tmp = ToDateTime(new LunarDate(year - 1, tmpMonth, tmpDay, false));
                                if (tmp.Date.Year < year)
                                    tmp = ToDateTime(new LunarDate(year + 1, tmpMonth, tmpDay, false));
                            }
                            break;
                        default:
                            break;
                    }
                    tmp = tmp.Date.AddDays(dayDiff);
                }
                else
                {
                    tmp = row.Field<DateTime>("RealDate").Date;
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Message);
            }

            return tmp;
        }
        
        static private bool CheckHoliday(DateTime date)
        {
            for (int i = 0; i < holidayDataTable.Rows.Count; i++)
            {
                DateTime d = holidayDataTable.Rows[i].Field<DateTime>("RealDate").Date;
                if (date.Date == d)
                    return true;
            }
            return false;
        }

        static public string GetHolidayName(DateTime date)
        {
            for (int i = 0; i < holidayDataTable.Rows.Count; i++)
            {
                DateTime d = holidayDataTable.Rows[i].Field<DateTime>("RealDate").Date;
                if (date.Date == d)
                    return holidayDataTable.Rows[i].Field<string>("name");
            }
            return "";
        }
        #endregion

        // Korean Lunar Functions ======================================================
        #region koreanLunar Functions
        static public LunarDate ToKoreanLunarDate(DateTime date)
        {
            int lunYear, lunMonth, lunDay, yunMonth;
            bool isYunMonth = false;

            KoreanLunisolarCalendar lunarDate = new KoreanLunisolarCalendar();

            lunYear = lunarDate.GetYear(date);
            lunMonth = lunarDate.GetMonth(date);
            lunMonth = lunarDate.GetMonth(date);
            lunDay = lunarDate.GetDayOfMonth(date);
            if (lunarDate.GetMonthsInYear(lunYear) > 12)
            {
                isYunMonth = lunarDate.IsLeapMonth(lunYear, lunMonth);
                yunMonth = lunarDate.GetLeapMonth(lunYear);
                if (lunMonth >= yunMonth)
                    lunMonth--;
            }
            return new LunarDate(lunYear, lunMonth, lunDay, isYunMonth);
        }

        static public DateTime ToDateTime(LunarDate lunDate)
        {
            int yunMonth;

            KoreanLunisolarCalendar lunarDate = new KoreanLunisolarCalendar();

            if (lunarDate.GetMonthsInYear(lunDate.lunYear) > 12)
            {
                yunMonth = lunarDate.GetLeapMonth(lunDate.lunYear);
                if (lunDate.isLunYun)
                    lunDate.lunMonth++;
                if (lunDate.lunMonth > yunMonth)
                    lunDate.lunMonth++;
            }

            return lunarDate.ToDateTime(lunDate.lunYear, lunDate.lunMonth, lunDate.lunDay, 0, 0, 0, 0);
        }
        #endregion

        // Internal Class ==============================================================
        #region Internal Class
        internal class LunarDate
        {
            public int lunYear;
            public int lunMonth;
            public int lunDay;
            public bool isLunYun;

            public LunarDate(int year, int month, int day, bool isYun)
            {
                lunYear = year;
                lunMonth = month;
                lunDay = day;
                isLunYun = isYun;
            }
        }
        #endregion
    }
}
